<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,shrink-to-fit=no"
    />
    <title>Nodes & Edges</title>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }

      html,
      body {
        height: 100%;
      }

      #container {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>

  <body>
    <div id="container"></div>
    <script
      src="../packages/g/dist/index.umd.min.js"
      type="application/javascript"
    ></script>
    <script
      src="../packages/g-webgl/dist/index.umd.min.js"
      type="application/javascript"
    ></script>
    <script
      src="../packages/g-plugin-dragndrop/dist/index.umd.min.js"
      type="application/javascript"
    ></script>
    <script>
      const { Circle, Line, Canvas, Text, CanvasEvent, runtime } = window.G;

      const NODE_NUM = 200000;
      const EDGE_NUM = 200000;

      // create a renderer
      const webglRenderer = new window.G.WebGL.Renderer();
      webglRenderer.registerPlugin(
        new window.G.Dragndrop.Plugin({
          isDocumentDraggable: true,
          isDocumentDroppable: true,
          dragstartDistanceThreshold: 10,
          dragstartTimeThreshold: 100,
        }),
      );

      // create a canvas
      const canvas = new Canvas({
        container: 'container',
        width: 600,
        height: 500,
        renderer: webglRenderer,
      });
      const camera = canvas.getCamera();

      canvas.addEventListener(CanvasEvent.READY, () => {
        let nodes = [];
        let texts = [];
        let colors = [
          '#965E04',
          '#C89435',
          '#F7A456',
          '#AFCF8A',
          '#7B39DE',
          '#B095C0',
          '#D24556',
          '#93C2FA',
          '#9DB09E',
          '#F8C821',
        ];
        let num = Math.floor(Math.sqrt(NODE_NUM) + 0.5);

        const sourceMap = new WeakMap();
        const targetMap = new WeakMap();
        for (let i = 0; i < NODE_NUM; i++) {
          const fill = colors[Math.floor(Math.random() * colors.length) || 0];
          const circle = new Circle({
            style: {
              cx: (i % num) * 10,
              cy: Math.floor(i / num) * 10,
              fill,
              r: 4,
              // draggable: true
            },
          });
          nodes.push(circle);
          sourceMap.set(circle, []);
          targetMap.set(circle, []);

          circle.addEventListener('mouseenter', () => {
            circle.style.fill = 'red';
            console.log('circle', i);
          });
          circle.addEventListener('mouseleave', () => {
            circle.style.fill = fill;
          });

          // if (i === NODE_NUM - 1) {
          //   const text = new Text({
          //     style: {
          //       x: (i % num) * 10,
          //       y: Math.floor(i / num) * 10,
          //       fontSize: 10,
          //       fill: 'black',
          //       text: `${i}`,
          //     },
          //   });
          //   texts.push(text);
          // }
        }

        for (let i = 0; i < EDGE_NUM; i++) {
          const source = nodes[Math.floor(Math.random() * NODE_NUM)];
          const target = nodes[Math.floor(Math.random() * NODE_NUM)];
          const line = new Line({
            style: {
              x1: source.style.cx,
              y1: source.style.cy,
              x2: target.style.cx,
              y2: target.style.cy,
              lineWidth: 0.3,
              stroke: 'grey',
            },
          });

          const sourceEdges = sourceMap.get(source);
          sourceEdges.push(line);
          const targetEdges = targetMap.get(target);
          targetEdges.push(line);

          canvas.appendChild(line);

          // line.addEventListener("mouseenter", () => {
          //   line.style.stroke = "red";
          // });
          // line.addEventListener("mouseleave", () => {
          //   line.style.stroke = "grey";
          // });
        }

        nodes.forEach((node) => {
          canvas.appendChild(node);
        });
        texts.forEach((text) => {
          canvas.appendChild(text);
        });

        let shiftX = 0;
        let shiftY = 0;
        function moveAt(target, canvasX, canvasY) {
          const x = canvasX - shiftX;
          const y = canvasY - shiftY;
          target.setPosition(x, y);
          const sourceEdges = sourceMap.get(target);
          const targetEdges = targetMap.get(target);
          sourceEdges.forEach((edge) => {
            edge.attr({
              x1: x,
              y1: y,
            });
          });
          targetEdges.forEach((edge) => {
            edge.attr({
              x2: x,
              y2: y,
            });
          });
        }

        canvas.addEventListener('dragstart', function (e) {
          // if (e.target === canvas.document) {
          // } else {
          //   const [x, y] = e.target.getPosition();
          //   shiftX = e.canvasX - x;
          //   shiftY = e.canvasY - y;
          //   moveAt(e.target, e.canvasX, e.canvasY);
          // }
        });
        canvas.addEventListener('drag', function (e) {
          // if (e.target === canvas.document) {
          camera.pan(-e.dx * 10, -e.dy * 10);
          // } else {
          //   moveAt(e.target, e.canvasX, e.canvasY);
          // }
        });

        // handle mouse wheel event
        const bindWheelHandler = () => {
          // update Camera's zoom
          // @see https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js
          const minZoom = 0;
          const maxZoom = Infinity;
          canvas
            .getContextService()
            .getDomElement() // g-canvas/webgl 为 <canvas>，g-svg 为 <svg>
            .addEventListener(
              'wheel',
              (e) => {
                // canvas.getConfig().disableHitTesting = true;
                e.preventDefault();
                let zoom;
                if (e.deltaY < 0) {
                  zoom = Math.max(
                    minZoom,
                    Math.min(maxZoom, camera.getZoom() / 0.95),
                  );
                } else {
                  zoom = Math.max(
                    minZoom,
                    Math.min(maxZoom, camera.getZoom() * 0.95),
                  );
                }
                camera.setZoom(zoom);
              },
              { passive: false },
            );
        };
        bindWheelHandler();
      });
    </script>
  </body>
</html>
